package com.gizwits

import com.gizwits.datapoint.DataPoint
import org.json4s._
import com.sun.org.apache.xml.internal.security.utils.Base64
import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException
import org.json4s.jackson.JsonMethods._
import com.gizwits.javautil.utils
import com.gizwits.javautil.utils._
import com.gizwits.util.{DataPointParse, UtilBits}
import jodd.util.Bits
import com.gizwits.util.CommonUtil._
//import spray.json

import scala.io.Source

//import org.apache.commons.codec.binary.{Hex, Base64}
object Base64Test2 {
  /**
   * @param simply_datapoint(attrs:JArray)
   * @param byte array 从业务指令数据的第二个byte开始,
   */
  def parse_data2str(arr_data_point:List[(String,String,String,Int,Int,Int,Int,String)],data:Array[Byte]):String={
    implicit lazy val formats = org.json4s.DefaultFormats
    var sb:StringBuilder = new StringBuilder("")
    //4 种大类
    var map = collection.mutable.Map("status_writable"->0,"status_readonly"->0,"alert"->0,"fault"->0)
    //计算大类中的 enum 与bool类型占据的byte长度
    for{dp <- arr_data_point}{
      var data_type = dp._2
      var status = dp._1
      var n_temp = map.getOrElse(status,0)
      data_type match {
        case "bool" => map(status) = n_temp+1
        case "enum" => map(status) = n_temp + dp._7
        case _ =>
      }
    }

    try{
      for{dp <- arr_data_point}{
        var data_type = dp._2
        var status = dp._1
        var name = dp._3
        var byte_index = dp._5
        var bit_index = dp._6
        var len = dp._7
        if(data_type == "bool"){
          var offset = 0
          var n_status = map.getOrElse(status, 0)
          offset = n_status>>3
          if(n_status%8!=0){
            offset +=1
          }
          offset -=1

          var r_o = bit_index%8
          var r_i = (byte_index+offset)-(bit_index>>3)
          if(r_i>=data.length){
            return ""
          }
          var bool_value = (data(r_i).toInt&0xff)>>(r_o)
          bool_value = bool_value&1
          sb.append(status.substring(0,1)+"_"+name).append("=").append(bool_value.toString).append(",");
        }else if(data_type == "enum"){
          var offset = 0
          var n_status = map.getOrElse(status, 0)
          offset = n_status>>3
          if(n_status%8!=0){
            offset +=1
          }
          offset -=1
          var r_i0 = (byte_index+offset)-(bit_index>>3)
          var r_i1 = (byte_index+offset)-((bit_index+len)>>3)
          var enum = dp._8.split("\t")
          var enum_value = 0
          if(r_i0>=data.length){
            return ""
          }
          for{k <- r_i0 to r_i1}{
            enum_value += (data(k).toInt&0xff)<<(Math.abs(k-r_i0)<<3)
          }
          var max = 0
          for(k <- 0 to len-1){
            max+=(1<<k)
          }
          var value = (enum_value>>(bit_index%8))&max
          if(value>=enum.length){
            return ""
          }
          var str_value = enum(value);
          if(str_value == ""){
            str_value = " "
          }
          sb.append(status.substring(0,1)+"_"+name).append("=").append(str_value).append(",");
        }else if(data_type == "uint8"){
          if(byte_index>=data.length){
            return ""
          }
          val Array(radio,addition,max,min) = dp._8.split("\t")
          var uint_8 = data(byte_index).toInt&0xff
          val f_ret = uint_8*radio.toFloat+addition.toFloat
          if(f_ret<min.toFloat || f_ret>max.toFloat){
            return ""
          }
          sb.append(status.substring(0,1)+"_"+name).append("=").append("%.2f".format(f_ret)).append(",");
        }else if(data_type == "uint16"){
          if(byte_index+2>data.length){
            return ""
          }

          val Array(radio,addition,max,min) = dp._8.split("\t")
          var uint_16 = ((data(byte_index).toInt&0xff)<<8)+(data(byte_index+1).toInt&0xff)
          val f_ret = uint_16*radio.toFloat+addition.toFloat
          if(f_ret<min.toFloat || f_ret>max.toFloat){
            return ""
          }
          sb.append(status.substring(0,1)+"_"+name).append("=").append("%.2f".format(f_ret)).append(",");
        }else if(data_type == "uint32"){
          if(byte_index+4>data.length){
            return ""
          }
          val Array(radio,addition,max,min) = dp._8.split("\t")
          var uint_32 = ((data(byte_index).toLong&0xff)<<24)+((data(byte_index+1).toLong&0xff)<<16)+((data(byte_index+2).toLong&0xff)<<8)+(data(byte_index+3).toLong&0xff)
          val f_ret = uint_32*radio.toFloat+addition.toFloat
          if(f_ret<min.toFloat || f_ret>max.toFloat){
            return ""
          }
          sb.append(status.substring(0,1)+"_"+name).append("=").append("%.2f".format(f_ret)).append(",");
        }else if(data_type == "binary"){
          var binary = new Array[Byte](len)
          if(byte_index+len>data.length){
            return ""
          }
          Array.copy(data, byte_index, binary, 0, len)
          var dp_value = Base64.encode(binary)
          dp_value = dp_value.replace("\n", "");
          sb.append(status.substring(0,1)+"_"+name).append("=").append(dp_value).append(",");
        }else{

        }
      }
    }catch {
      case t:ArrayIndexOutOfBoundsException=>{// todo: handle error
        println(arr_data_point.toString())
        println(data.length)
      }
    }
    return if(sb.toString() == "") sb.toString() else sb.substring(0,sb.length-1)
  }
  def simply_datapoint(arr_data_point:JArray):List[(String,String,String,Int,Int,Int,Int,String)]={
    var s_list = List[(String,String,String,Int,Int,Int,Int,String)]()
    implicit lazy val formats = org.json4s.DefaultFormats
    for{i <- 0 to arr_data_point.arr.length-1}{
      var dp = arr_data_point(i)
      var data_type = (dp \ "data_type").extract[String]
      var status = (dp \ "type").extract[String]
      var position = (dp \ "position")
      var name = (dp \ "name").extract[String]
      var byte_index = (position \ "byte_offset").extract[Int]
      var bit_index = (position \ "bit_offset").extract[Int]
      var len = (position \ "len").extract[Int]
      data_type match {
        case "enum" => s_list = s_list ++ List((status,data_type,name,0,byte_index,bit_index,len,(dp \ "enum").extract[List[String]].mkString("\t")))
        case "uint8" => s_list = s_list ++ List((status,data_type,name,1,byte_index,bit_index,len,((dp \ "uint_spec") \ "ratio").extract[String]+"\t"+((dp \ "uint_spec") \ "addition").extract[String]+"\t"+((dp \ "uint_spec") \ "max").extract[String]+"\t"+((dp \ "uint_spec") \ "min").extract[String]))
        case "uint16"  => s_list = s_list ++ List((status,data_type,name,1,byte_index,bit_index,len,((dp \ "uint_spec") \ "ratio").extract[String]+"\t"+((dp \ "uint_spec") \ "addition").extract[String]+"\t"+((dp \ "uint_spec") \ "max").extract[String]+"\t"+((dp \ "uint_spec") \ "min").extract[String]))
        case "uint32"  => s_list = s_list ++ List((status,data_type,name,1,byte_index,bit_index,len,((dp \ "uint_spec") \ "ratio").extract[String]+"\t"+((dp \ "uint_spec") \ "addition").extract[String]+"\t"+(if(((dp \ "uint_spec") \ "max").isInstanceOf[JObject]) (((dp \ "uint_spec") \ "max") \ "$numberLong").extract[String] else ((dp \ "uint_spec") \ "max").extract[String]) +"\t"+(if(((dp \ "uint_spec") \ "min").isInstanceOf[JObject]) (((dp \ "uint_spec") \ "min") \ "$numberLong").extract[String] else ((dp \ "uint_spec") \ "min").extract[String])))
        case "bool" => s_list = s_list ++ List((status,data_type,name,1,byte_index,bit_index,len," "))
        case "binary" => s_list = s_list ++ List((status,data_type,name,1,byte_index,bit_index,len," "))
      }
    }
    s_list
  }
  def main(args: Array[String]) {

    val s="AAAAAyIAAJEEAAAAAAABAAAA6wAAAN8AAAB+AAAANgAAAAAAAABk"
    //val s="AAAAAw4AAJEEAAAAAAEcHQAAog=="
    //val b= Base64.decodeBase64(s)
    implicit val formats = DefaultFormats
    //   url   https://github.com/json4s/json4s
    val path=this.getClass.getResource("/Dita_Airkiss.json").getPath
    println(path)
    val j=Source.fromFile(path)
    // j.getLines().foreach(println _)
    val json2=j.getLines().mkString("")

    println(json2)

    val js= parse(json2)

    var attrs=(js \ "entities") \"attrs"
     println(attrs)
     val b=Base64.decode(s)
    println(get_msg_len(b))
    val bit=b.slice(b.length-(get_msg_len(b)._2),b.length)
   println(bit.toList)

    println(parse_data2str(simply_datapoint(attrs.asInstanceOf[JArray]),bit))

    println(DataPointParse.parse(attrs.asInstanceOf[JArray],bit))
//     println(get_msg_len(b))  //(1,30)
//
//    println(b.toList)
//    val bit=b.slice(b.length-(get_msg_len(b)._2),b.length)
//      println(bit.toList)
//    println(UtilBits.byte2bool(bit.slice(0,1)))
//    println(utils.byte2bits(bit(0)))
//    println(utils.byte2bits(bit(5)))
//    println(UtilBits.byte2Uint32(bit.slice(1,5)))
//    println(UtilBits.byte2bool(bit.slice(5,6)))
//    println(UtilBits.byte2Uint32(bit.slice(6,10)))
//    println(UtilBits.byte2Uint32(bit.slice(10,14)))



    ///
  }

}
